package service

import (
	"context"
	"fmt"
	"math/rand"

	pb "verifyCode/api/verifyCode"
)

const (
	DigitSet  = "0123456789"
	LetterSet = "abcdefghijklmnopqrstuvwxyz"
	MixedSet  = DigitSet + LetterSet
)

type VerifyCodeService struct {
	pb.UnimplementedVerifyCodeServer
}

func NewVerifyCodeService() *VerifyCodeService {
	return &VerifyCodeService{}
}

func (s *VerifyCodeService) GetVerifyCode(ctx context.Context, req *pb.GetVerifyCodeRequest) (*pb.GetVerifyCodeReply, error) {
	var chars string
	switch req.Type {
	case pb.TYPE_DEFAULT:
		fallthrough
	case pb.TYPE_DIGIT:
		chars = DigitSet
	case pb.TYPE_LETTER:
		chars = LetterSet
	case pb.TYPE_MIXED:
		chars = MixedSet
	default:
	}
	return &pb.GetVerifyCodeReply{Code: randCode(chars, int(req.Length))}, nil
}

func randCode(chars string, length int) string {
	charsLen := len(chars)
	if charsLen == 0 {
		return ""
	}
	result := make([]byte, length)
	idxBits := len(fmt.Sprintf("%b", length))
	idxMask := 1<<idxBits - 1
	idxMax := 64 / idxBits
	for i, cache, remain := 0, rand.Int63(), idxMax; i < length; {
		if idxMax == 0 {
			cache, remain = rand.Int63(), idxMax
		}
		if randIndex := int(cache & int64(idxMask)); randIndex < charsLen {
			result[i] = chars[randIndex]
			i++
		}
		cache >>= int64(idxBits)
		remain--
	}
	return string(result)
}
